package net.homeip.jcperera.nu.model.entity;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.PrePersist;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;

import net.homeip.jcperera.nu.core.boot.Boot;
import net.homeip.jcperera.nu.core.persistence.GlobalSequence;
import net.homeip.jcperera.nu.security.user.User;

import org.eclipse.persistence.annotations.Index;

/**
 * Persistent Entity, the base of all Persistent Entities in the Framework
 * 
 * @name Persistent Entity Base class
 * @author julio.c.perera@gmail.com
 * @application nu
 * @since 0.1.0.0
 */

@Entity
@Table(name = PersistentEntity.tableName)
@Named(PersistentEntity.componentName)
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class PersistentEntity extends BaseEntity implements Serializable
{
    // Required to implement Serializable interface
    private static final long  serialVersionUID          = -659149739053050764L;

    // CoreBase properties, for easy use from other components, as well as logging
    public static final int    runtimeLevel              = 1;
    public static final String moduleName                = "model";
    public static final String componentName             = "nu_model_base_persistent_entity";
    
    // All persistent entities should specify a table name
    public static final String tableName                 = "PERSISTENT_ENTITY";
    
    public static final String globalVersionSequenceName = "ENTITY_GLOBALVERSION_SEQ";

    @Inject
    @Transient
    private User               user;

    @Id
    @Column(name = "ENTITY_ID", length = 36)
    private String             entityid                  = null;

    @Basic(optional = false)
    @Column(name = "CREATED_BY")
    private String             createdBy                 = "";

    @Basic(optional = false)
    @Column(name = "CREATED_WHEN", insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar           createdWhen               = Calendar.getInstance();

    @Basic(optional = false)
    @Column(name = "MODIFIED_BY")
    private String             modifiedBy                = "";

    @Basic(optional = false)
    @Column(name = "MODIFIED_WHEN", insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar           modifiedWhen              = Calendar.getInstance();

    @Basic(optional = false)
    @Column(name = "LOCAL_VERSION")
    @Version
    private long               localVersion;

    @Basic(optional = false)
    @Column(name = "GLOBAL_VERSION")
    @SequenceGenerator(name = "EntityGlobalVersionSequence", sequenceName = globalVersionSequenceName, allocationSize = 1, initialValue = 1)
    @GeneratedValue(generator = "EntityGlobalVersionSequence", strategy = GenerationType.SEQUENCE)
    @Index(name = "ENTITY_GLOBALVERSION_NDX")
    private long               globalVersion;

    @Basic(optional = false)
    @Column(name = "DELETED")
    private Boolean            deleted                   = false;

    public PersistentEntity()
    {
        super();
    }

    public String getEntityid()
    {
        return entityid;
    }

    public Calendar getModifiedWhen()
    {
        return modifiedWhen;
    }
    
    public Date getModifiedWhenAsDate()
    {
        return (modifiedWhen == null? null : modifiedWhen.getTime());
    }
    
    public long getLocalVersion()
    {
        return localVersion;
    }

    public long getGlobalVersion()
    {
        return globalVersion;
    }

    public User getUser()
    {
        return user;
    }

    public String getCreatedBy()
    {
        return createdBy;
    }

    public Calendar getCreatedWhen()
    {
        return createdWhen;
    }

    public Date getCreatedWhenAsDate()
    {
        return (createdWhen == null? null : createdWhen.getTime());
    }
    
    public String getModifiedBy()
    {
        return modifiedBy;
    }

    public Boolean getDeleted()
    {
        return deleted;
    }

    @PrePersist
    protected void beforePersist()
    {
        if (user == null) user = Boot.getSystem().getSystemUser();
        if (entityid == null)
        {
            entityid = UUID.randomUUID().toString();
            createdBy = user.getName();
            createdWhen = Calendar.getInstance();
        }
        modifiedBy = this.user.getName();
        modifiedWhen = Calendar.getInstance();
        globalVersion = GlobalSequence.getNextValue(globalVersionSequenceName);
    }
}
